﻿// 实现一个简单的汇编器
#include "BinIns.h"
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

// 初始化汇编指令集
static void InitAssembleInstructions(vector<string> &assIns)
{
  assIns.clear();

  assIns.push_back("HLT");
  assIns.push_back("JMP");
  assIns.push_back("CJMP");
  assIns.push_back("OJMP");
  assIns.push_back("CALL");
  assIns.push_back("RET");
  assIns.push_back("PUSH");

  assIns.push_back("POP");

  assIns.push_back("LOADB");
  assIns.push_back("LOADW");
  assIns.push_back("STOREB");
  assIns.push_back("STOREW");
  assIns.push_back("LOADI");
  assIns.push_back("NOP");
  assIns.push_back("IN");
  assIns.push_back("OUT");
  assIns.push_back("ADD");
  assIns.push_back("ADDI");
  assIns.push_back("SUB");
  assIns.push_back("SUBI");
  assIns.push_back("MUL");
  assIns.push_back("DIV");
  assIns.push_back("AND");
  assIns.push_back("OR");
  assIns.push_back("NOR");
  assIns.push_back("NOTB");
  assIns.push_back("SAL");
  assIns.push_back("SAR");
  assIns.push_back("EQU");
  assIns.push_back("LT");
  assIns.push_back("LTE");
  assIns.push_back("NOTC ");
  assIns.push_back("BYTE");
  assIns.push_back("WORD");
}

// 初始化
// 指令-参数个数
static void InitInstrctionArgNumber(map<BinIns, int> &insArgNum)
{
  insArgNum.clear();

  insArgNum[BinIns::binHLT] = 0;
  insArgNum[BinIns::binJMP] = 1;
  insArgNum[BinIns::binCJMP] = 1;
  insArgNum[BinIns::binOJMP] = 1;
  insArgNum[BinIns::binCALL] = 1;
  insArgNum[BinIns::binRET] = 0;
  insArgNum[BinIns::binPUSH] = 1;
  insArgNum[BinIns::binPOP] = 1;
  insArgNum[BinIns::binLOADB] = 1;
  insArgNum[BinIns::binLOADW] = 1;
  insArgNum[BinIns::binSTOREB] = 1;
  insArgNum[BinIns::binSTOREW] = 1;
  insArgNum[BinIns::binLOADI] = 2;
  insArgNum[BinIns::binNOP] = 0;
  insArgNum[BinIns::binIN] = 2;
  insArgNum[BinIns::binOUT] = 2;
  insArgNum[BinIns::binADD] = 3;
  insArgNum[BinIns::binADDI] = 2;
  insArgNum[BinIns::binSUB] = 3;
  insArgNum[BinIns::binSUBI] = 2;
  insArgNum[BinIns::binMUL] = 3;
  insArgNum[BinIns::binDIV] = 3;
  insArgNum[BinIns::binAND] = 3;
  insArgNum[BinIns::binOR] = 3;
  insArgNum[BinIns::binNOR] = 3;
  insArgNum[BinIns::binNOTB] = 3;
  insArgNum[BinIns::binSAL] = 3;
  insArgNum[BinIns::binSAR] = 3;
  insArgNum[BinIns::binEQU] = 2;
  insArgNum[BinIns::binLT] = 2;
  insArgNum[BinIns::binLTE] = 2;
  insArgNum[BinIns::binNOTC] = 0;
  insArgNum[BinIns::binInvalid] = 1;
}

static void InitRegisterToBinary(map<string, int> &regisToBin)
{
  regisToBin["R0"] = 0;
  regisToBin["R1"] = 1;
  regisToBin["R2"] = 2;
  regisToBin["R3"] = 3;
  regisToBin["R4"] = 4;
  regisToBin["R5"] = 5;
  regisToBin["R6"] = 6;
  regisToBin["R7"] = 7;
}

// 建立汇编指令到二进制指令的映射
// 初始化
static void InitAssembleToBinary(const vector<string> &assIns,
                                 map<string, BinIns> &assToBin)
{
  assToBin.clear();
  for (auto i = 0; i != assIns.size(); ++i)
  {
    // assIns和BinIns的指令次序一致
    assToBin[assIns[i]] = static_cast<BinIns>(i);
  }
}

static string StringToUpper(const string &str)
{
  string ret;
  for (auto i = 0; i != str.size(); ++i)
  {
    ret += toupper(str[i]);
    if (str[i] == ':')
    {
      ret += '\t';
    }
  }
  return ret;
}

static void AssembleToBinary(const vector<string> &ass,
                             vector<Instruction> &bin,
                             const map<string, BinIns> &assToBin,
                             map<BinIns, int> &insArgNum,
                             map<string, int> &regisToBin)
{
  map<string, int> label;
  int rownum = 0;
  // 将ass汇总
  for (auto i = 0; i != ass.size(); ++i)
  {
    string assline;
    assline = StringToUpper(ass[i]) + '\t';

    // cout << assline << endl;

    istringstream sin(assline);
    string strOp, strArg;
    Instruction ins;
    BinIns op;
    int arg;
    while (sin >> strOp)
    {
      auto cit = assToBin.find(strOp);
      if (cit == assToBin.end())
      {
        // 没有找到对应的指令码
        // 忽略处理
        if (strOp[0] != '#' && strOp.back() != ':')
          throw "输入非法指令！！";

        if (strOp.back() == ':')
        {
          label[strOp.substr(0, strOp.length() - 1)] = 4 * rownum;
          continue;
        }
        if (strOp[0] == '#')
        {
          rownum--;
          continue;
        }
      }
      op = cit->second;
      // insArgNum为非const型
      // assToBin const型保障了insArgNum[]不会存在更新的情况
      int argNum = insArgNum[op];
      if (argNum > 0)
      {
        int n = argNum;
        for (int j = 0; j < n; j++)
        {

          sin >> strArg;
          auto cittemp = regisToBin.find(strArg);
          auto citlabel = label.find(strArg);
          if (cittemp == regisToBin.end() && citlabel == label.end())
          {
            // 没有找到对应的寄存器码，也不是标号
            // 即是立即数
            arg = atoi(strArg.c_str());
            ins.arg[j] = arg;
          }
          else if (cittemp != regisToBin.end())
          {
            arg = cittemp->second;
            ins.arg[j] = arg;
          }
          else
          {
            arg = citlabel->second;
            ins.arg[j] = arg;
          }
          // arg = atoi(strArg.c_str());
          // ins.arg[i] = arg;
        }
      }

      ins.op = op;

      bin.push_back(ins);
    }
    rownum++;
  }
}

static string IntToString(int n, int sizeofbytes)
{
  string ret;
  ret.resize(sizeofbytes * 8, '0');
  for (int i = ret.size() - 1; i >= 0 && n != 0; --i, n /= 2)
  {
    ret[i] = n % 2 + '0';
  }
  return ret;
}

#ifdef __LIB__
// 汇编指令集
static vector<string> assIns;
// 二进制指令-操作数个数
static map<BinIns, int> insArgNum;
// 汇编指令到二进制的映射
static map<string, BinIns> assToBin;
static map<string, int> regisToBin;
void InitAssembler()
{
  InitAssembleInstructions(assIns);

  InitInstrctionArgNumber(insArgNum);

  InitAssembleToBinary(assIns, assToBin);

  InitRegisterToBinary(regisToBin);
}

/**
 * @brief 汇编指令转二进制指令
 * @param 存放汇编指令的文本
 * @return 转译完成的二进制指令文本
 */
string Asm2Bin(const string &Asm)
{
  vector<string> ass;
  ass.clear();
  string line;
  stringstream AsmIns(Asm);
  while (getline(AsmIns, line))
  {
    ass.push_back(line);
  }
  vector<Instruction> bin; // 保存二进制指令
  AssembleToBinary(ass, bin, assToBin, insArgNum, regisToBin);

  string bins;
  stringstream BinIns(bins);
  for (auto i = 0; i != bin.size(); ++i)
  {
    BinIns << IntToString(bin[i].op, 1);
    for (int j = 0; j < 3; j++)
    {
      int arg = bin[i].arg[j];
      BinIns << IntToString(arg, 1);
    }
    BinIns << '\n';
  }
  return BinIns.str();
}
#else

// 读入汇编指令
static void ReadAssemble(vector<string> &ass)
{
  ass.clear();
  string line;
  while (getline(cin, line))
  {
    ass.push_back(line);
  }
}

// 显示
static void Display(const vector<string> &bar)
{
  for (auto i = 0; i != bar.size(); ++i)
  {
    cout << bar[i] << endl;
  }
}

void OutputBinary(const vector<Instruction> &bin,
                  const map<BinIns, int> &insArgNum)
{
  for (auto i = 0; i != bin.size(); ++i)
  {
    // cout << i+1<<" ";
    // cout << bin[i].op<<" ";
    cout << IntToString(bin[i].op, 1);
    auto cit = insArgNum.find(bin[i].op);
    if (cit == insArgNum.end())
    {
      // 如果没有找到
      // 不做处理
      continue;
    }
    for (int j = 0; j < 3; j++)
    {
      int arg = bin[i].arg[j];
      cout << IntToString(arg, 1);
    }
    /*if (cit->second > 0)
    {
      cout << '\t' << bin[i].arg;
      cout << '\t' << IntToString(bin[i].arg, 4);
    }*/
    cout << endl;
  }
}

int main()
{
  // 汇编指令集
  vector<string> assIns;
  InitAssembleInstructions(assIns);

  // 二进制指令-操作数个数
  map<BinIns, int> insArgNum;
  InitInstrctionArgNumber(insArgNum);

  // 汇编指令到二进制的映射
  map<string, BinIns> assToBin;
  InitAssembleToBinary(assIns, assToBin);

  map<string, int> regisToBin;
  InitRegisterToBinary(regisToBin);
  vector<string> ass; // 保持读入的汇编指令
  ReadAssemble(ass);

  cout << endl;
  Display(ass);
  cout << endl;

  vector<Instruction> bin; // 保存二进制指令
  AssembleToBinary(ass, bin, assToBin, insArgNum, regisToBin);

  OutputBinary(bin, insArgNum);

  cout << endl;

  return 0;
}

#endif
